package com.mingyuean.demo.mybatis.io;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;

/**
 * @author MingYueAn
 * <p>  加载全局配置文件
 * <p>  辅助类，它提供了一些获取资源的方法和加载类的方法
 * <p>  2023/3/16 21:35
 * @version: 1.0
 */
public class Resources {

    /**
     * 根据配置文件的路径，将配置文件加载成字符输入流的形式
     *
     * @param path 全局配置文件的路径
     * @return 配置文件对应的字符输入流
     * @throws IOException 如果找不到对应的资源，则抛出此异常
     */
    public static Reader getResourceAsReader(String path) throws IOException {
        // 获取配置文件对应的字节输入流，并用 InputStreamReader 将其转化为字符流
        return new InputStreamReader(getResourceAsStream(path));
    }

    /**
     * 根据配置文件的路径，将配置文件加载成字节输入流的形式
     *
     * @param path 全局配置文件的路径
     * @return 配置文件对应的字节输入流
     * @throws IOException 如果找不到对应的资源，则抛出此异常
     */
    public static InputStream getResourceAsStream(String path) throws IOException {
        // 从系统中所有的类加载器和当前线程上下文类加载器中逐个查找资源
        final ClassLoader[] classLoaders = getClassLoaders();
        for (ClassLoader classLoader : classLoaders) {
            // 通过类加载器获取配置文件的字节输入流，如果找到了就返回该流
            final InputStream resourceAsStream = classLoader.getResourceAsStream(path);
            if (null != resourceAsStream) {
                return resourceAsStream;
            }
        }
        // 如果所有的类加载器都没有找到对应的资源，则抛出异常
        throw new IOException("无法找到资源" + path);
    }

    /**
     * 返回一个包含系统类加载器和当前线程上下文类加载器的数组，
     * 用于在资源搜索过程中逐个查询
     *
     * @return 返回一个包含系统类加载器和当前线程上下文类加载器的数组
     */
    private static ClassLoader[] getClassLoaders() {
        return new ClassLoader[]{
                // 获取系统类加载器
                ClassLoader.getSystemClassLoader(),
                // 获取当前线程上下文类加载器
                Thread.currentThread().getContextClassLoader()
        };
    }

    /**
     * 根据类名获取对应的类对象
     *
     * @param className 类的全限定名
     * @return 类对象
     * @throws ClassNotFoundException 如果找不到对应的类，则抛出此异常
     */
    public static Class<?> classForName(String className) throws ClassNotFoundException {
        return Class.forName(className);
    }
}